import { _decorator, Asset, assetManager, error } from "cc";
import { Singleton } from "../decorators/Singleton";
const { ccclass } = _decorator;

type LoadProgress = (
  completedCount: number,
  totalCount: number,
  item: any
) => void;

@Singleton
@ccclass("ResourceManager")
export class ResourceManager {
  private _assetMap: Map<string, Asset> = new Map();

  constructor() {}

  public loadAsset<T extends Asset>(
    path: string,
    type: new (...args: any[]) => T
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      if (this._assetMap.has(path)) {
        resolve(this._assetMap.get(path) as T);
        return;
      }

      assetManager.loadAny({ path }, (err: Error | null, asset: T) => {
        if (err) {
          error(`Failed to load asset: ${path}`, err);
          reject(err);
          return;
        }

        this._assetMap.set(path, asset);
        resolve(asset);
      });
    });
  }

  public loadDir(dir: string, onProgress?: LoadProgress): Promise<Asset[]> {
    return new Promise((resolve, reject) => {
      assetManager.loadAny(
        { dir },
        (err: Error | null, assets: Asset[]) => {
          if (err) {
            error(`Failed to load directory: ${dir}`, err);
            reject(err);
            return;
          }

          assets.forEach((asset) => {
            this._assetMap.set(asset.name, asset);
          });
          resolve(assets);
        },
        onProgress
      );
    });
  }

  public getAsset<T extends Asset>(path: string): T | null {
    return (this._assetMap.get(path) as T) || null;
  }

  public releaseAsset(path: string): void {
    const asset = this._assetMap.get(path);
    if (asset) {
      asset.decRef();
      this._assetMap.delete(path);
    }
  }

  public releaseAll(): void {
    this._assetMap.forEach((asset) => {
      asset.decRef();
    });
    this._assetMap.clear();
  }
}
